// Copyright (C), 2012-2018, Sichuan Xiaoka Technology Co., Ltd.
package crypto;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.*;
import java.util.Map.Entry;

/**
 * Map工具类.
 * 
 * @author 李杰
 *
 */
public class MapUtil {

/**.
 * 升序排序.
 */
public static final String MAP_SORT_ORDER_DESC = "desc";

  /**.
   * 降序排序.
   */
  public static final String MAP_SORT_ORDER_ASC = "asc";

  /**.
   * Map和Bean互转时用来存放判断条件Class集合.
   */
  private static final List<Class<?>> MAP_UTIL_CLAZZ_LIST = new ArrayList<Class<?>>();

  /**
   * 静态初始化
   */
  static {
    MAP_UTIL_CLAZZ_LIST.add(char.class);
    MAP_UTIL_CLAZZ_LIST.add(byte.class);
    MAP_UTIL_CLAZZ_LIST.add(short.class);
    MAP_UTIL_CLAZZ_LIST.add(int.class);
    MAP_UTIL_CLAZZ_LIST.add(long.class);
    MAP_UTIL_CLAZZ_LIST.add(float.class);
    MAP_UTIL_CLAZZ_LIST.add(double.class);
    MAP_UTIL_CLAZZ_LIST.add(boolean.class);
    MAP_UTIL_CLAZZ_LIST.add(Character.class);
    MAP_UTIL_CLAZZ_LIST.add(Byte.class);
    MAP_UTIL_CLAZZ_LIST.add(Short.class);
    MAP_UTIL_CLAZZ_LIST.add(String.class);
    MAP_UTIL_CLAZZ_LIST.add(Integer.class);
    MAP_UTIL_CLAZZ_LIST.add(Long.class);
    MAP_UTIL_CLAZZ_LIST.add(Float.class);
    MAP_UTIL_CLAZZ_LIST.add(Double.class);
    MAP_UTIL_CLAZZ_LIST.add(Boolean.class);
    MAP_UTIL_CLAZZ_LIST.add(Date.class);
    MAP_UTIL_CLAZZ_LIST.add(java.sql.Date.class);
    MAP_UTIL_CLAZZ_LIST.add(Timestamp.class);
    MAP_UTIL_CLAZZ_LIST.add(BigInteger.class);
    MAP_UTIL_CLAZZ_LIST.add(BigDecimal.class);
  }

  /**
   * map转Object
   * 
   * @param map
   *          数据map
   * @param clazz
   *          接收转换数据类
   * @return
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   * @throws InstantiationException
   */
  public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz)
      throws IllegalArgumentException, IllegalAccessException,
      InstantiationException {

    if (map == null || map.isEmpty() ){
      return null;
    }

    T obj = clazz.newInstance();
    Field[] fields = obj.getClass().getDeclaredFields();
    for (Field f : fields) {
      f.setAccessible(true);
      String name = f.getName();
      Class<?> type = f.getType();
      for (String key : map.keySet()) {
        Object value = map.get(key);
        // 如果属性名和map中的key一致
        if (name.equals(key) && MAP_UTIL_CLAZZ_LIST.contains(type)) {
          if (type.equals(char.class)) {
            f.set(obj, (char) value);
          } else if (type.equals(byte.class)) {
            f.set(obj, (byte) value);
          } else if (type.equals(short.class)) {
            f.set(obj, (short) value);
          } else if (type.equals(int.class)) {
            f.set(obj, (int) value);
          } else if (type.equals(long.class)) {
            f.set(obj, (long) value);
          } else if (type.equals(float.class)) {
            f.set(obj, (float) value);
          } else if (type.equals(double.class)) {
            f.set(obj, (char) value);
          } else if (type.equals(boolean.class)) {
            f.set(obj, (boolean) value);
          } else if (type.equals(Character.class)) {
            f.set(obj, (Character) value);
          } else if (type.equals(Byte.class)) {
            f.set(obj, (Byte) value);
          } else if (type.equals(Short.class)) {
            f.set(obj, (Short) value);
          } else if (type.equals(String.class)) {
            f.set(obj, (String) value);
          } else if (type.equals(Integer.class)) {
            f.set(obj, (Integer) value);
          } else if (type.equals(Long.class)) {
            f.set(obj, (Long) value);
          } else if (type.equals(Float.class)) {
            f.set(obj, (Float) value);
          } else if (type.equals(Double.class)) {
            f.set(obj, (Double) value);
          } else if (type.equals(Boolean.class)) {
            f.set(obj, (Boolean) value);
          } else if (type.equals(Date.class)) {
            f.set(obj, (Date) value);
          } else if (type.equals(java.sql.Date.class)) {
            f.set(obj, (java.sql.Date) value);
          } else if (type.equals(Timestamp.class)) {
            f.set(obj, (Timestamp) value);
          } else if (type.equals(BigInteger.class)) {
            f.set(obj, (BigInteger) value);
          } else if (type.equals(BigDecimal.class)) {
            f.set(obj, (BigDecimal) value);
          } else {
            f.set(obj, value);
          }
          // 名称一致，但是类型列表中没有该类型
        } else if (name.equals(key) && !MAP_UTIL_CLAZZ_LIST.contains(type)) {
          f.set(obj, value);
          // 都不存在，有可能是应用的其他对象
        } else if (!name.equals(key) && !MAP_UTIL_CLAZZ_LIST.contains(type)) {
          Object object = mapToObject(map, type);
          f.set(obj, object);
          // 名称不一致，不管
        } else if (!name.equals(key) && MAP_UTIL_CLAZZ_LIST.contains(type)) {

        }
      }
    }
    return obj;
  }

  /**
   * Object转Map
   * 
   * @param obj
   *          转换数据对象
   * @return
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   */
  public static Map<String, Object> objectToMap(Object obj)
      throws IllegalArgumentException, IllegalAccessException {

    if (obj == null || "".equals(obj)){
      return null;
    }
    Map<String, Object> map = new HashMap<>(16);
    Field[] fields = obj.getClass().getDeclaredFields();
    for (Field f : fields) {
      f.setAccessible(true);
      String name = f.getName();
      Object value = f.get(obj);
      Class<?> type = f.getType();
      if (MAP_UTIL_CLAZZ_LIST.contains(type)) {
        if (type.equals(char.class)) {
          map.put(name, (char) value);
        } else if (type.equals(byte.class)) {
          map.put(name, (byte) value);
        } else if (type.equals(short.class)) {
          map.put(name, (short) value);
        } else if (type.equals(int.class)) {
          map.put(name, (int) value);
        } else if (type.equals(long.class)) {
          map.put(name, (long) value);
        } else if (type.equals(float.class)) {
          map.put(name, (float) value);
        } else if (type.equals(double.class)) {
          map.put(name, (char) value);
        } else if (type.equals(boolean.class)) {
          map.put(name, (boolean) value);
        } else if (type.equals(Character.class)) {
          map.put(name, (Character) value);
        } else if (type.equals(Byte.class)) {
          map.put(name, (Byte) value);
        } else if (type.equals(Short.class)) {
          map.put(name, (Short) value);
        } else if (type.equals(String.class)) {
          map.put(name, (String) value);
        } else if (type.equals(Integer.class)) {
          map.put(name, (Integer) value);
        } else if (type.equals(Long.class)) {
          map.put(name, (Long) value);
        } else if (type.equals(Float.class)) {
          map.put(name, (Float) value);
        } else if (type.equals(Double.class)) {
          map.put(name, (Double) value);
        } else if (type.equals(Boolean.class)) {
          map.put(name, (Boolean) value);
        } else if (type.equals(Date.class)) {
          map.put(name, (Date) value);
        } else if (type.equals(java.sql.Date.class)) {
          map.put(name, (java.sql.Date) value);
        } else if (type.equals(Timestamp.class)) {
          map.put(name, (Timestamp) value);
        } else if (type.equals(BigInteger.class)) {
          map.put(name, (BigInteger) value);
        } else if (type.equals(BigDecimal.class)) {
          map.put(name, (BigDecimal) value);
        } else {
          map.put(name, value);
        }
      } else {
        Map<String, Object> secondMap = objectToMap(value);
        for (String key : secondMap.keySet()) {
          map.put(key, secondMap.get(key));
        }
      }
    }
    return map;
  }

  /**
   * 按照Map的键[KEY]排序
   * 
   * @param map
   *          要排序的Map
   * @param sortOrder
   *          排序方式
   * @return
   */
  public static Map<String, Object> mapSortByKey(Map<String, Object> map,
      String sortOrder) {
    Map<String, Object> treeMap = new TreeMap<String, Object>(
        new Comparator<String>() {
          @Override
          public int compare(String o1, String o2) {
            if (sortOrder.toLowerCase().equals(MAP_SORT_ORDER_ASC)) {
              // 按KEY升序
              return o1.compareTo(o2);
            } else if (sortOrder.toLowerCase().equals(MAP_SORT_ORDER_DESC)) {
              // 按KEY降序;
              return o2.compareTo(o1);
            } else {
              // 默认按KEY升序
              return o1.compareTo(o2);
            }
          }
        });
    Iterator<Entry<String, Object>> entries = map.entrySet().iterator();
    while (entries.hasNext()) {
        Entry<String, Object> entry = entries.next();
        treeMap.put(entry.getKey(), entry.getValue());
    }
    return treeMap;
  }

  /**
   * 按照Map的值[VALUE]排序，这里的Map的值为String类型，如果要使用其他类型可以再添加方法
   *
   * @param map
   *          要排序的Map
   * @param sortOrder
   *          排序方式
   * @return
   */
  public static Map<String, String> mapSortByValue(Map<String, String> map,
      String sortOrder) {
    Map<String, String> sortMap = new LinkedHashMap<String, String>();
    List<Entry<String, String>> list = new ArrayList<Entry<String, String>>(
            // 这里将map.entrySet()转换成list
        map.entrySet());
    // 然后通过比较器来实现排序
    Collections.sort(list, new Comparator<Entry<String, String>>() {
          @Override
          public int compare(Entry<String, String> o1, Entry<String, String> o2) {
            if (sortOrder.toLowerCase().equals(MAP_SORT_ORDER_ASC)) {
              // 按VALUE升序
              return (o1.getValue()).compareTo(o2.getValue());
            } else if (sortOrder.toLowerCase().equals(MAP_SORT_ORDER_DESC)) {
              // 按VALUE降序;
              return (o2.getValue()).compareTo(o1.getValue());
            } else {
              // 默认按VALUE升序
              return (o1.getValue()).compareTo(o2.getValue());
            }
          }
        });
    for (Entry<String, String> entry : list) {
      sortMap.put(entry.getKey(), entry.getValue());
    }
    return sortMap;
  }
}
